<template>
  <div class="container">
    <el-row :gutter="10">
      <el-col :span="6">
        <div class="card-container">
          <el-card :body-style="{ padding: '5px' }" shadow="never">
            <template #header>
              <div class="card-header">
                <el-row :gutter="10" style="width: 100%" align="middle">
                  <el-col :span="8">
                    <span class="card-title">功能菜单</span>
                  </el-col>
                  <el-col :span="16">
                    <div class="card-btn">
                      <div>
                        <el-button
                          icon="Remove"
                          v-auth="['menu/sc']"
                          type="warning"
                          @click="handleMenuDelete"
                        >
                          删除
                        </el-button>
                      </div>
                      <div>
                        <el-tooltip
                          content="点击新增后请在右侧输入内容后保存"
                          effect="dark"
                          placement="right"
                        >
                          <el-button
                            icon="Plus"
                            v-auth="['menu/xz']"
                            type="primary"
                            @click="handleMenuAdd(true)"
                          >
                            新增
                          </el-button>
                        </el-tooltip>
                      </div>
                    </div>
                  </el-col>
                </el-row>
              </div>
            </template>
            <div class="card-content-full">
              <div style="display: flex; align-items: center">
                <el-input
                  v-model="state.searchKey"
                  clearable
                  placeholder="输入名称/编码搜索"
                  prefix-icon="search"
                />
                <el-button
                  type="primary"
                  icon="search"
                  @click="handleSearchQuery"
                />
              </div>
              <el-tree
                ref="menuTreeRef"
                accordion
                :check-strictly="false"
                lazy
                :load="lazyLoadNode"
                class="custom-tree"
                :data="menuTree.dataList"
                :default-expanded-keys="state.defaultExpandedKey"
                highlight-current
                node-key="id"
                :props="menuTree.props"
                :show-checkbox="true"
                @node-click="handleNodeClick"
              >
                <template #default="{ node, data }">
                  <div>
                    <span v-if="data.iconCls">
                      <IconifyIconOnline :icon="data.iconCls" />
                    </span>
                    {{ node.label }}
                  </div>
                </template>
              </el-tree>
            </div>
          </el-card>
        </div>
      </el-col>
      <el-col :span="18">
        <div class="card-container">
          <vab-card shadow="never">
            <div class="card-content-full">
              <el-tabs
                ref="tabsRef"
                v-model="state.currentTabs"
                :stretch="true"
                type="border-card"
              >
                <el-tab-pane label="菜单信息" name="0">
                  <el-form
                    ref="menuFormRef"
                    label-position="left"
                    label-width="80px"
                    :model="state.menuFormData"
                    :rules="menuFormRules"
                  >
                    <el-row :gutter="10">
                      <el-col :span="12">
                        <el-form-item label="资源类型" prop="menuType">
                          <DictSelect
                            ref="menuTypeRef"
                            v-model:defaultValue="state.menuFormData.menuType"
                            dict-code="1018"
                            show-all="N"
                            expanding
                            @change="handleMenuTypeChange"
                          />
                        </el-form-item>
                      </el-col>
                      <el-col :span="12">
                        <el-form-item label="所属上级" prop="pid">
                          <el-input
                            v-model="state.menuFormData.pname"
                            :disabled="true"
                            placeholder="请选择所属上级"
                            style="width: 80%"
                          >
                            <template #append>
                              <el-button
                                icon="search"
                                @click="openMenuPicker"
                              />
                            </template>
                          </el-input>
                          <el-button
                            :icon="Delete"
                            type="danger"
                            @click="handleResetParant"
                          />
                        </el-form-item>
                      </el-col>
                      <el-col :span="12">
                        <el-form-item label="资源名称" prop="menuName">
                          <el-input
                            v-model="state.menuFormData.menuName"
                            :maxlength="50"
                            placeholder="资源名称"
                            :show-word-limit="true"
                            @change="handleMenuNameChange"
                          />
                        </el-form-item>
                      </el-col>

                      <el-col :span="12">
                        <el-form-item label="资源编码" prop="menuCode">
                          <el-input
                            v-model="state.menuFormData.menuCode"
                            :maxlength="40"
                            placeholder="资源编码"
                            :show-word-limit="true"
                            style="width: 80%"
                            @change="handleMenuCodeChange"
                          >
                            <template #append>
                              <el-button
                                icon="refresh"
                                @click="handleMenuCodeRefresh"
                              />
                            </template>
                          </el-input>
                          <el-tooltip
                            content="资源编码用于标识路由/按钮权限"
                            effect="dark"
                            placement="right"
                          >
                            <el-icon><Warning /></el-icon>
                          </el-tooltip>
                        </el-form-item>
                      </el-col>
                      <el-col :span="12">
                        <el-form-item label="图标" prop="iconName">
                          <el-popover
                            :disabled="state.menuUrlDisabled"
                            :width="450"
                            trigger="click"
                            popper-class="pure-popper"
                            :popper-options="{
                              placement: 'auto'
                            }"
                            @show="handleIconShow"
                            @hide="handleIconHide"
                          >
                            <template #reference>
                              <el-button style="width: 160px">
                                <IconifyIconOnline
                                  :icon="state.menuFormData.iconName"
                                  :size="40"
                                />
                                {{
                                  state.menuFormData.iconName
                                    ? state.menuFormData.iconName
                                    : "请选择图标"
                                }}
                                <el-icon><ArrowDownBold /></el-icon>
                              </el-button>
                            </template>
                            <IconPicker
                              ref="iconPickerRef"
                              @handle-icon="handleIcon"
                              v-model="state.menuFormData.iconName"
                            />
                          </el-popover>
                          <el-button
                            :icon="Delete"
                            type="danger"
                            @click="handleIconCancel"
                          />
                        </el-form-item>
                      </el-col>
                      <el-col :span="12">
                        <el-form-item label="排序号" prop="orderId">
                          <el-input
                            v-model="state.menuFormData.orderId"
                            placeholder="排序号"
                            type="number"
                          />
                        </el-form-item>
                      </el-col>
                      <el-col :span="12">
                        <el-form-item label="组件名称" prop="componentName">
                          <el-input
                            v-model="state.menuFormData.componentName"
                            :disabled="state.menuUrlDisabled"
                            :maxlength="128"
                            placeholder="请输入组件名称"
                            :show-word-limit="true"
                          />
                        </el-form-item>
                      </el-col>
                      <el-col :span="12">
                        <el-form-item label="路由地址" prop="routePath">
                          <el-input
                            v-model="state.menuFormData.routePath"
                            :disabled="state.menuUrlDisabled"
                            :maxlength="128"
                            placeholder="请输入组件路由地址"
                            :show-word-limit="true"
                          />
                        </el-form-item>
                      </el-col>
                      <el-col :span="24">
                        <el-form-item label="组件/地址" prop="componentUrl">
                          <div
                            style="
                              display: flex;
                              justify-content: flex-start;
                              align-items: center;
                              width: 100%;
                            "
                          >
                            <el-select
                              v-model="state.menuFormData.componentType"
                              @change="handleComponentTypeChange"
                              :disabled="state.menuUrlDisabled"
                              style="width: 20%"
                            >
                              <el-option label="根目录组件" value="Layout" />
                              <el-option label="子目录组件" value="Container" />
                              <el-option label="页面组件" value="Page" />
                              <el-option label="应用功能组件" value="Module" />
                              <el-option label="表单组件" value="Form" />
                            </el-select>
                            <el-button
                              icon="Search"
                              v-if="
                                state.menuFormData.componentType === 'Module'
                              "
                              @click="handleOpenModulePicker"
                              >选择应用功能</el-button
                            >
                            <el-button
                              icon="Search"
                              v-if="state.menuFormData.componentType === 'Form'"
                              @click="handleOpenFormPicker"
                              >选择应用功能</el-button
                            >
                            <el-input
                              v-model="state.menuFormData.componentUrl"
                              :disabled="
                                state.menuUrlDisabled ||
                                state.menuFormData.componentType !== 'Page'
                              "
                              :maxlength="128"
                              :placeholder="componentUrlPlaceHolder"
                              :show-word-limit="true"
                              style="width: 60%"
                            />
                          </div>
                        </el-form-item>
                      </el-col>
                      <el-col
                        :span="24"
                        v-if="
                          state.menuFormData.componentType != 'Layout' &&
                          state.menuFormData.componentType != 'Container' &&
                          !state.menuUrlDisabled
                        "
                      >
                        <el-form-item label="路由参数" prop="routeParams">
                          <div>
                            <div style="display: block">
                              <el-tag
                                type="primary"
                                v-for="(item, index) in state.menuFormData
                                  .routeParamsJson"
                                :key="index"
                                closable
                                hit
                                @close="handleDeleteParam(index)"
                                style="margin-right: 20px"
                              >
                                `{{ item.paramName }}:{{ item.paramValue }}`
                              </el-tag>
                            </div>
                            <div>
                              <el-text style="margin-right: 20px"
                                >参数名</el-text
                              >
                              <el-input
                                v-model="paramsItem.paramName"
                                type="text"
                                style="width: 150px"
                              />
                              <el-text
                                style="margin-left: 20px; margin-right: 20px"
                                >参数值</el-text
                              ><el-input
                                v-model="paramsItem.paramValue"
                                type="text"
                                style="width: 150px; margin-right: 20px"
                              />
                              <el-button type="primary" @click="handleAddParam"
                                >新增</el-button
                              >
                            </div>
                          </div>
                        </el-form-item>
                      </el-col>
                      <el-col :span="24">
                        <el-form-item label="备注" prop="remark">
                          <el-input
                            v-model="state.menuFormData.remark"
                            :maxlength="256"
                            placeholder="备注"
                            :rows="1"
                            :show-word-limit="true"
                            type="textarea"
                          />
                        </el-form-item>
                      </el-col>
                      <el-col :span="24" style="text-align: center">
                        <el-button
                          icon="DocumentChecked"
                          type="primary"
                          @click="onMenuSaveSubmit()"
                          v-auth="['menu/xg']"
                        >
                          保存
                        </el-button>
                      </el-col>
                    </el-row>
                  </el-form>
                </el-tab-pane>
                <el-tab-pane name="1">
                  <template #label>
                    <span>
                      <i class="el-icon-user">关联资源</i>
                      <el-badge size="mini" :value="state.menuResourceNum" />
                    </span>
                  </template>
                  <ResourceMain ref="resourceRef" :show-query="false" />
                </el-tab-pane>
              </el-tabs>
            </div>
          </vab-card>
        </div>
      </el-col>
    </el-row>
    <MenuPicker ref="menuPickerRef" @change="handleMenuPicker" />
    <DefModulePicker ref="defModulePickerRef" @change="handleModuleChange" />
    <DefFormPicker ref="defFormPickerRef" @change="handleFormChange" />
  </div>
</template>
<script setup name="Menu">
import { reactive } from "vue";
import { Delete } from "@element-plus/icons-vue";
import {
  queryMenuTree,
  updateMenu,
  addMenu,
  deleteMenu,
  queryValid
} from "@/api/admin/system/menu/";
import DictSelect from "@/components/dictSelect.vue";
import MenuPicker from "@/components/menuTreePicker.vue";
import ResourceMain from "@/views/admin/system/resource/main.vue";
import DefModulePicker from "@/components/def/defModulePicker.vue";
import DefFormPicker from "@/components/formPicker.vue";
import IconPicker from "@/components/iconPicker.vue";
import { useTree } from "@/hooks/tree";
import { useMessage, useMessageBox } from "@/hooks/message";
import pinyin from "js-pinyin";

const state = reactive({
  searchKey: "",
  currentTabs: "0",
  menuFormData: {
    operationAdd: true,
    id: "",
    menuName: "",
    menuCode: "",
    orderId: "",
    menuType: "1",
    pid: "0",
    pcode: "",
    pname: "无",
    routePath: "",
    componentType: "Layout",
    componentUrl: "",
    componentName: "",
    routeParams: "",
    routeParamsJson: [],
    iconName: "",
    remark: ""
  },
  menuResourceNum: 0,
  defaultExpandedKey: [],
  menuUrlDisabled: false
});

const menuTreeRef = ref(null);
const menuFormRef = ref(null);
const menuTypeRef = ref(null);
const menuPickerRef = ref(null);
const resourceRef = ref(null);
const tabsRef = ref(null);
const iconPickerRef = ref(null);
const defModulePickerRef = ref(null);
const defFormPickerRef = ref(null);
const componentUrlPlaceHolder = ref("请输入组件地址或者组件名称");
const menuFormRules = ref({
  menuType: [{ required: true, message: "资源类型不能为空", trigger: "blur" }],
  menuName: [
    { required: true, message: "资源名称不能为空", trigger: "blur" },
    { max: 50, message: "资源名称不能超过50个字符", trigger: "blur" }
  ],
  menuCode: [
    { required: true, message: "资源编码不能为空", trigger: "blur" },
    { max: 40, message: "资源编码不能超过40个字符", trigger: "blur" },
    {
      validator: async (rule, value, callback) => {
        if (value === "") {
          callback(new Error("资源编码不能为空"));
        } else {
          const res = await queryValid(state.menuFormData);
          if (res.code !== 200) {
            callback(new Error(res.msg));
          }
        }
      },
      trigger: "change"
    }
  ],
  remark: [{ max: 256, message: "备注不能超过256个字符", trigger: "blur" }]
});

const paramsItem = reactive({
  paramName: "",
  paramValue: ""
});

const treeOptions = reactive({
  queryForm: {},
  props: {
    children: "children",
    label: "text",
    isLeaf: "leaf"
  },
  autoLoad: true,
  ascs: ["order_id"],
  queryFunction: queryMenuTree
});

const {
  instance: menuTree,
  queryTreeData,
  lazyLoadNode
} = useTree(treeOptions);

onMounted(() => {
  queryTreeData();
});

const handleSearchQuery = async () => {
  if (state.searchKey) {
    queryTreeData({ pid: null, searchKey: state.searchKey });
  } else {
    queryTreeData({ pid: "0", searchKey: null });
  }
};

const handleIconShow = () => {
  iconPickerRef.value.show();
};

const handleIconHide = () => {
  iconPickerRef.value.close();
};

const openMenuPicker = () => {
  menuPickerRef.value.show();
};

const handleOpenModulePicker = () => {
  defModulePickerRef.value.show();
};

const handleModuleChange = rows => {
  const index = state.menuFormData.routeParamsJson.findIndex(item => {
    return item.paramName === "moduleId";
  });
  if (index !== -1) {
    state.menuFormData.routeParamsJson[index]["paramValue"] = rows.id;
  } else {
    state.menuFormData.routeParamsJson.push({
      paramName: "moduleId",
      paramValue: rows.id
    });
  }
};

const handleOpenFormPicker = () => {
  defFormPickerRef.value.show();
};

const handleFormChange = rows => {
  const index = state.menuFormData.routeParamsJson.findIndex(item => {
    return item.paramName === "formId";
  });
  if (index !== -1) {
    state.menuFormData.routeParamsJson[index]["paramValue"] = rows[0].id;
  } else {
    state.menuFormData.routeParamsJson.push({
      paramName: "formId",
      paramValue: rows[0].id
    });
  }
};

const handleComponentTypeChange = type => {
  if (type === "Layout") {
    state.menuFormData.componentUrl = "Layout";
  } else if (type === "Container") {
    state.menuFormData.componentUrl = "Container";
  } else if (type === "Module") {
    state.menuFormData.componentUrl = "def/module/render";
  } else if (type === "Form") {
    state.menuFormData.componentUrl = "flow/form/render";
  } else if (type === "Page") {
    state.menuFormData.componentUrl = "";
    componentUrlPlaceHolder.value =
      "请输入vue文件在views下的地址,如:admin/system/menu/index";
  }
};

const handleAddParam = () => {
  state.menuFormData.routeParamsJson.push({
    paramName: paramsItem.paramName,
    paramLabel: paramsItem.paramLabel
  });
  paramsItem.paramName = "";
  paramsItem.paramValue = "";
};

const handleDeleteParam = index => {
  state.menuFormData.routeParamsJson.splice(index, 1);
};

const handleMenuPicker = nodes => {
  if (nodes && nodes.length > 0) {
    state.menuFormData.pid = nodes[0].id;
    state.menuFormData.pname = nodes[0].text;
    state.menuFormData.pcode = nodes[0].menuCode;
    if (state.menuFormData.menuType != "2") {
      if (!state.menuFormData.menuCode) {
        state.menuFormData.menuCode = pinyin
          .getCamelChars(state.menuFormData.menuName)
          .toLowerCase();
      }
      state.menuFormData.routePath =
        nodes[0].routePath + "/" + state.menuFormData.menuCode;
    } else {
      if (!state.menuFormData.menuCode) {
        state.menuFormData.menuCode = `${nodes[0].menuCode}/${pinyin
          .getCamelChars(state.menuFormData.menuName)
          .toLowerCase()}`;
      }
    }
  }
};

const handleMenuNameChange = val => {
  if (val) {
    if (state.menuFormData.menuType != "2") {
      let menuCode;
      if (!state.menuFormData.menuCode) {
        menuCode = pinyin.getCamelChars(val);
        state.menuFormData.menuCode = menuCode.toLowerCase();
        state.menuFormData.componentName =
          menuCode.substring(0, 1).toUpperCase() +
          menuCode.substring(1).toLowerCase();
        state.menuFormData.componentUrl = "Layout";
      }
    } else {
      if (!state.menuFormData.menuCode) {
        const menuCode = `${state.menuFormData.pcode}/${pinyin
          .getCamelChars(val)
          .toLowerCase()}`;
      }
      state.menuFormData.menuCode = menuCode;
      state.menuFormData.componentName = "";
      state.menuFormData.componentUrl = "";
    }
  }
};

const handleMenuTypeChange = val => {
  state.menuFormData.menuType = val;
  if (val === "1") {
    state.menuUrlDisabled = false;
    if (!state.menuFormData.menuCode) {
      state.menuFormData.menuCode = pinyin
        .getCamelChars(state.menuFormData.menuName)
        .toLowerCase();
    }
  }
  //按钮
  else if (val === "2") {
    state.menuFormData.routePath = "";
    state.menuFormData.componentName = "";
    state.menuFormData.componentUrl = "";
    state.menuFormData.componentName = "";
    state.menuFormData.componentType = "";
    state.menuFormData.routeParams = "";
    state.menuFormData.iconName = "";
    state.menuUrlDisabled = true;
  }
};

const handleMenuCodeChange = val => {
  state.menuFormData.componentName =
    val.substring(0, 1).toUpperCase() + val.substring(1);
};

const handleMenuCodeRefresh = () => {
  if (state.menuFormData.menuName) {
    state.menuFormData.menuCode = pinyin
      .getCamelChars(state.menuFormData.menuName)
      .toLowerCase();
  } else {
    useMessage().warning("请先输入资源名称");
  }
};

const handleNodeClick = async data => {
  state.menuFormData.operationAdd = false;
  state.menuFormData.id = data.id;
  state.menuFormData.menuName = data.text;
  if (data.menuCode) {
    state.menuFormData.menuCode = data.menuCode;
  }
  state.menuFormData.orderId = data.orderId;
  state.menuFormData.menuType = data.menuType;
  state.menuFormData.pid = data.pid;
  state.menuFormData.pcode = "";
  if (data.pname) {
    state.menuFormData.pname = data.pname;
  } else {
    state.menuFormData.pname = "无";
  }
  state.menuFormData.routePath = data.routePath;
  state.menuFormData.componentUrl = data.componentUrl;
  state.menuFormData.componentName = data.componentName;
  state.menuFormData.componentType = data.componentType;
  state.menuFormData.routeParams = data.routeParams;
  if (data.routeParams) {
    state.menuFormData.routeParamsJson = JSON.parse(data.routeParams);
  }
  if (data.iconName) {
    state.menuFormData.iconName = data.iconName;
  } else {
    state.menuFormData.iconName = "";
  }
  state.menuFormData.remark = data.remark;
  await resourceRef.value
    .show({ id: data.id, menuFullName: data.menuFullName })
    .then(res => {
      state.menuResourceNum = resourceRef.value.getTotal();
    });
};

const handleMenuDelete = () => {
  const checkedNodes = menuTreeRef.value.getCheckedNodes();
  if (checkedNodes.length < 1) {
    useMessage().success("未选中任何资源");
  } else {
    useMessageBox()
      .confirm("删除的资源将无法恢复，是否继续")
      .then(async res => {
        const ids = checkedNodes.map(item => item.id).join();
        const { msg } = await deleteMenu(ids);
        useMessage().success(msg);
        queryTreeData();
      });
  }
};

const handleMenuAdd = btnclick => {
  state.menuFormData.operationAdd = true;
  state.menuFormData.id = "";
  state.menuFormData.menuCode = "";
  state.menuFormData.menuName = "";
  state.menuFormData.menuType = menuTypeRef.value.getValue();
  state.menuFormData.menuName = "";
  if (btnclick) {
    state.menuFormData.pid = "0";
    state.menuFormData.pcode = "";
    state.menuFormData.pname = "无";
  }
  state.menuFormData.orderId = "";
  state.menuFormData.routePath = "";
  state.menuFormData.componentType = "Layout";
  state.menuFormData.componentUrl = "";
  state.menuFormData.componentName = "";
  state.menuFormData.routeParams = "";
  state.menuFormData.routeParamsJson = [];
  state.menuFormData.iconName = "";
  state.menuFormData.remark = "";
  state.currentTabs = "0";
};

const onMenuSaveSubmit = () => {
  menuFormRef.value.validate(async valid => {
    if (valid) {
      if (state.menuFormData.componentType === "Module") {
        if (state.menuFormData.routeParamsJson.length === 0) {
          useMessage().warning("请选择应用功能");
          return;
        }
      }
      if (state.menuFormData.menuType === "1") {
        if (!state.menuFormData.routePath) {
          useMessage().warning("请配置路由地址");
          return;
        }
      }
      const params = {
        id: state.menuFormData.id,
        menuName: state.menuFormData.menuName,
        menuCode: state.menuFormData.menuCode,
        orderId: state.menuFormData.orderId,
        menuType: state.menuFormData.menuType,
        pid: state.menuFormData.pid,
        routePath: state.menuFormData.routePath,
        componentType: state.menuFormData.componentType,
        componentUrl: state.menuFormData.componentUrl,
        componentName: state.menuFormData.componentName,
        routeParams: JSON.stringify(state.menuFormData.routeParamsJson),
        iconName: state.menuFormData.iconName,
        remark: state.menuFormData.remark
      };
      if (!state.menuFormData.operationAdd) {
        updateMenu(params).then(res => {
          if (res.code === 200) {
            useMessage().success(res.msg);
            queryTreeData();
            state.defaultExpandedKey = [res.data.id];
          } else {
            useMessage().error(res.msg);
          }
        });
      } else {
        addMenu(params).then(res => {
          if (res.code === 200) {
            useMessage().success(res.msg);
            queryTreeData();
            if (state.menuFormData.operationAdd) {
              handleMenuAdd(false);
            }
            state.defaultExpandedKey = [res.data.id];
          } else {
            useMessage().error(res.msg);
          }
        });
      }
    }
  });
};

const handleIcon = item => {
  state.menuFormData.iconName = item;
};

const handleIconCancel = () => {
  state.menuFormData.iconName = "";
};

const handleResetParant = () => {
  state.menuFormData.pid = "0";
  state.menuFormData.pname = "无";
};
</script>
<style lang="scss" scoped></style>
